#include <Ice/Application.h>
#include <IceUtil/Thread.h>
#include <Glacier2/Glacier2.h>
#include <Yafridng.h>
#include <YafridngRendererFactoryI.h>

using namespace std;
using namespace Yafridng;

class SessionRefreshThread : public IceUtil::Thread, public IceUtil::Monitor<IceUtil::Mutex>
{
public:
  
  SessionRefreshThread(const IceUtil::Time& timeout, const Yafridng::RenderSessionPrx& session) :
    _session(session),
    _timeout(timeout),
    _destroyed(false)
  {
  }
  
  virtual void
  run()
  {
    Lock sync(*this);
    while(!_destroyed)
      {
	timedWait(_timeout);
	if(!_destroyed)
	  {
	    try
	      {
		cout << "Keeping alive" << endl;
		_session->keepAlive();
	      }
	    catch(const Ice::Exception& ex)
	      {
		cerr << "SessionRefreshThread: " << ex << endl;
		_destroyed = true;
		exit(1);
	      }
	  }
      }
  }
  
  void
  destroy()
  {
    Lock sync(*this);
    _destroyed = true;
    notify();
  }
  
private:  
  const Yafridng::RenderSessionPrx _session;
  const IceUtil::Time _timeout;
  bool _destroyed;
};
typedef IceUtil::Handle<SessionRefreshThread> SessionRefreshThreadPtr;

class YafridngProvider
  : virtual public Ice::Application
{
public:

  int registerNewNode(){

    Ice::RouterPrx defaultRouter = communicator()->getDefaultRouter();
    if(!defaultRouter)
      {
	cerr << ": no default router stablished" << endl;
	return EXIT_FAILURE;
      }
    
    Glacier2::RouterPrx router = Glacier2::RouterPrx::checkedCast(defaultRouter);
    if(!router)
      {
	cerr << ": configured router is not a glacier2 router" << endl;
	return EXIT_FAILURE;
      }
    
    Yafridng::RenderSessionPrx session;
    try{
      session = Yafridng::RenderSessionPrx::uncheckedCast(router->createSessionFromSecureConnection());
    }
    
    catch(const Glacier2::PermissionDeniedException& ex){
      cout << "Permission denied:\n" << ex.reason << endl;
      return 1;
    }
    
    SessionRefreshThreadPtr refresh =
      new SessionRefreshThread(IceUtil::Time::seconds(router->getSessionTimeout()/2),
			       session);
    refresh->start();
    Ice::ObjectAdapterPtr adapter = communicator()->createObjectAdapter("YafridngNodeAdapter");
    string category = router->getServerProxy()->ice_getIdentity().category;
    Identity RenderingNodeIdentity;
    RenderingNodeIdentity.name = "RenderingNode";
    RenderingNodeIdentity.category = category;
    YafridngRendererFactoryPrx factory = Yafridng::YafridngRendererFactoryPrx::uncheckedCast
      (adapter->add(new YafridngRendererFactoryI(category), RenderingNodeIdentity));
    adapter->activate();
    session->addNode(factory);

    communicator()->waitForShutdown();
  }
  virtual int run (int argc,
		   char *argv[])
  {
    registerNewNode();
    return EXIT_SUCCESS;
  }
};

int main(int argc,
	 char* argv[])
{
  YafridngProvider config;
  return config.main(argc, argv);
}
